好好的吃頓飯也是一種優雅。刪除也是。
「如何把陣列或元素清空」也要寫一篇? 妳當牛肉麵在寫嗎?
自從有了這本「JavaScript 大全」當枕頭,阿不是,才發現自己真是懵懂無知,但求知識不嫌遲,只能盡量腦補,讓自己盡量處於知道 JavaScript 到底做了什麼的狀態~結論是:路,還很長。
原本以為 Javascript 像某些語言ㄧ樣,可以控制記憶體或把某部分的記憶體釋放出來,就在網路上開始找如何刪除變數的文章,結果搜尋結果清一色是在講,如何刪除「陣列裡的元素」這件事,才發現 JavaScript 似乎沒有完全把變數刪除這件事,我們也看不見記憶體的存取或清空的狀態,只能用一些機制來驗證。結論是對陣列 Array 來說,沒有把陣列刪除變數這件事,似乎就只能把陣列清空,而不能刪除變數。 自己無法作主的人生 !But...請看下去~
在「JavaScript 大全」裡 p55 有說明:
1.如果用let
來宣告變數,創立的特性會是nonconfigurable
也就是不可配置的,這個變數是不可用delete
這個運算子刪除。
2.如果不是在strict
模式底下,將值指定給一個為宣告的變數,JavaScript 會自動為我們創建一個全域變數,用這種方式創建的變數具有configurable
特性,也就是可以被delete
運算子刪除。
第一點說的宣告,其實也包括了用let
和const
來宣告變數,我們可以可以用簡單的方式來測試一下:
let a = 42;
delete a; // false
console.log(a); // 42
let b = 42;
delete b; // false
console.log(b); // 42
const c = 42;
delete c; // false
console.log(c); // 42
d = 42;
delete d; // true
console.log(d) // Uncaught ReferenceError: d is not defined
變數 d
就真的這樣被刪除掉了!
那麼其他不是透過Delete
刪除的變數,是怎麼被全域環境清除掉的?
JavaScript 有一種清理 廚餘的機制,是一種垃圾收集器(garbage collector),它會在變數不再被使用的時候出現,並釋放掉不再使用的記憶體,當然,變數也就這樣真的刪除掉了。
終於要進入今天的主題了:刪除陣列元素 在拖什麼啊
將空陣列[]直接指派給要清除的 Array,這種方式其實不算清空,比較像是我們拿另一塊空的記憶體,重新指派給這個變數。
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1 = [];
arr1; // []
arr2; // [1, 2, 3, 4, 5, 6]
可以確定的是,如果我們複製了一份,複製的那份將不會受到原陣列的影響。
這一種方式和底下幾種清除陣列元素的方式,有一個很大的不同,就是使用重新指派的方式清空陣列,如arr1 =[]
,因為重新指派,所以即使在這之前有做陣列複製如arr2 = arr1
,兩個陣列也不會互相影響。
直接將陣列的長度length
歸0
,這種方式效能會比較好。但是,恩湯恩湯。因為複製於這個陣列的其他陣列,也會被改變。也就是說是以參考同一個記憶體位置by Reference
的方式進行複製。
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1.length = 0;
arr1; // []
arr2; // []
splice()通常是拿來刪除陣列裡的某個元素,當然也可以拿來刪除元素,但是splice()本身並不會複製一份新陣列,而是會指向原陣列的位址,所以原陣列被刪除的元素,複製過來的陣列元素也同時會被刪除。
splice()的用法在後面的篇章會有更詳盡的介紹。
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1; // [1, 2, 3, 4, 5, 6]
arr1.splice(0, arr1.length);
arr1; // []
arr2; // []
利用while
迴圈與陣列長度,使用pop()
從尾端刪除陣列元素的功能遍歷陣列,一一從尾端清除陣列元素,pop()
同樣是就地改變的方法,所以也會同時改動到被複製出來的陣列。我們在前幾章有講到控制陣列長度的特有屬性:Length,有興趣的可以參考一下。
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1; // [1, 2, 3, 4, 5, 6]
while (arr1.length) {
arr1.pop();
}
arr1; // []
arr2; // []
以上三種方法,都是在複製陣列時,以參考同一個記憶體位置by Reference
的方式進行複製,所以使用arr1.length = 0
的方式清空陣列,則所複製出來的陣列arr2 = arr1
的arr2
會受原來的arr1
影響,同時被清空,所以將arr1.length = 0
也等於將arr2
清空。
在文章最初,我們介紹了用delete
運算子來刪除整個陣列,但其實它比較常被拿來清除陣列的某一元素。直接清除陣列元素的方法delete
,個人覺得這也不算真的清除,只是把這個元素回歸為空的狀態,也就是 empty(undefined)。我們可以以length
來驗證陣列元素並不會因為使用delete
而改變長度。
let arr1 = [1, 2, 3, 4, 5]
arr1.length; // 5 -> arr1 陣列的長度
delete arr1[1]; // true -> 刪除索引值為1的元素
arr1; // [1, empty, 3, 4, 5] -> 被刪除的元素變成 empty 空的了。
arr1.length; // 5 -> arr1 陣列的長度仍是5
1 in arr1; // false -> 確認索引值 1 在 arr1 陣列裡有沒有值
arr1[1] = 2; // 將 2 指定給剛剛刪除的索引值 1
刪除陣列的元素,類似將undefined
指定給該元素,但仍和empty
會有些微差距嘛?這點還需要驗證。要特別注意的是,用delete
刪元素並不會改變陣列的長度,且此陣列就成為一個「稀疏」的陣列。
使用「稀疏」陣列會造成什麼影響?有時候我們希望用一些方法來處理陣列,然後把處理完的結果回傳回來,如果陣列裡有稀疏的狀態,那麼當我麼用方法去遍歷陣列元素時,就會回傳 undefined
。
let arr1 = [1, 2, 3, 4, 5];
delete arr1[1]; // 刪除某一元素陣列後的陣列 -> [1, empty, 3, 4, 5]
let arr2 = arr1.map(function(x){
return x * 2;
}); // 用 map() 遍歷每個元素將其 * 2
arr2; // 回傳結果 -> [2, empty, 6, 8, 10]
有時候我們會拿到有許多無效 被搞爛的元素在陣列裡,如何刪除陣列裡這些無所事事的undefined
、null
、0
或其他的元素?讓處理陣列資料時更順利?我們可以利用 JavaScript 的while
迴圈,來遍歷陣列內容,一一來把我們過濾過後,要保留的元素留在陣列中。
function filter_array(testArray) {
let index = -1,
arrLength = testArray ? testArray.length : 0,
resIndex = -1,
result = [];
while (++index < arrLength) {
let value = testArray[index];
if (value != null && value !== '' && value !== undefined && !isNaN(value) && value !== false && value !== 0) {
result[++resIndex] = value;
}
}
return result;
}
filter_array([NaN, 0, 15, false, -22, '',undefined, 47, null]); // [15, -22, 47]
相信大家在看完這一篇之後,會對於刪除陣列或元素有更加深的認識。老實說,真心覺得鐵人賽最大的收穫,是在寫文章的時候,找到的資料有吸收,且發現原來這麼多方法與面向,真的是一件很有趣的事啊! 且前幾天收到一些大大的回饋,無論是指定或提問,都讓本人雀躍不已,在每一次的交流中,更可以加深自己對 JavaScript 的理解,實在感謝!
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~